#include "NearestMeanClassifier.h"

#include "DataSet.h"
#include "Sample.h"
#include<limits> 	
#include <iostream>

NearestMeanClassifier::NearestMeanClassifier()
{

}

NearestMeanClassifier::~NearestMeanClassifier()
{

}

int NearestMeanClassifier::test(const Sample& s) const
{  //init
  unsigned int nearest(-1);
  float distance(-1),best(std::numeric_limits<float>::max());
  // for all prototypes measure distance (in all dimensions)
  for(unsigned int candidate=0; candidate < means_.size();++candidate){
	  distance=0;
	  for(unsigned int dimension=0; dimension < means_[1].size() ;++dimension){
		  distance+=   (s.input(dimension) - means_[candidate][dimension])
			         * (s.input(dimension) - means_[candidate][dimension]);
	  } 
	  //distance=sqrt(distance); // assume euclidian metric
	  if(distance < best){
		  best=distance;
		  nearest=candidate;//remember the best fit
	  }
  }
  return nearest; // return it
}


void NearestMeanClassifier::train(const DataSet& ds)
{
	// init
	std::cout << "\n nr_samples "<< ds.samples().size() << "\n";
	std::cout << "\n nr_features "<< ds.sample(0).input().size() << "\n";
  int current_label(0),
	  size(ds.samples().size()),
	  features(ds.sample(0).input().size()),
	  max(-1);
  // find max label - assume number of labels
  for(int s=0; s < size; ++s){
	if(ds.label(s) > max)
		max = ds.sample(s).label();
  }
  nrClasses_ = max+1; // for sake of simplicity I assume, that all natural numbers are classes between 0 and 'max'...

  means_.resize(nrClasses_);//init 2D vec.	   
  for(unsigned int lab=0; lab < means_.size(); ++lab)
	means_[lab].resize(features,0);   

  std::vector<int> num(nrClasses_,0);  // to calculate incremental average
  for(int s=0; s < size; ++s){  // for all samples...
    current_label=ds.label(s);  // remember its label
	num[current_label]++;
	for(int ft=0; ft < features; ++ft){ // add its features to the means
		means_[current_label][ft] +=  (ds.sample(s).input(ft)
								        -means_[current_label][ft])
									  /num[current_label]; // incremental mean
	}
  }
}